<template>
  <el-submenu index="5" :popper-append-to-body="false">
    <template slot="title">工具箱</template>
    <el-menu-item index="5-1" @click="spaceMeasureFun('LineString')">
      <ruler
        theme="two-tone"
        size="27"
        :fill="['#ffffff', '#000000']"
        :strokeWidth="3"
        strokeLinejoin="miter"
        strokeLinecap="butt"
      />
      测量距离
    </el-menu-item>
    <el-menu-item index="5-2" @click="spaceMeasureFun('Polygon')">
      <multi-triangular
        theme="two-tone"
        size="27"
        :fill="['#ffffff', '#000000']"
        :strokeWidth="3"
        strokeLinejoin="miter"
        strokeLinecap="butt"
      />
      测量面积
    </el-menu-item>
    <el-menu-item index="5-3" @click="removeMeasureFun()">
      <rectangle-x
        theme="two-tone"
        size="27"
        :fill="['#ffffff', '#000000']"
        :strokeWidth="3"
        strokeLinejoin="miter"
        strokeLinecap="butt"
      />
      关闭测量
    </el-menu-item>
    <el-menu-item index="5-4" @click="exportImg()">
      <outbound
        theme="two-tone"
        size="27"
        :fill="['#ffffff', '#000000']"
        :strokeWidth="3"
        strokeLinejoin="miter"
        strokeLinecap="butt"
      />
      导出图片
    </el-menu-item>
  </el-submenu>
</template>

<script>
import { mapState } from 'vuex'
import { Ruler, MultiTriangular, RectangleX, Outbound } from '@icon-park/vue'
var sketch = null //当前绘制的要素
var overLayerList = [] //标注图层
export default {
  name: 'toolBox',
  components: { Ruler, MultiTriangular, RectangleX, Outbound },
  data() {
    return {
      draw: null, //画笔
      helpTooltipElement: null, //帮助提示框对象
      helpTooltip: null, //帮助提示框显示的信息
      measureTooltipElement: null, //测量工具提示框对象
      measureTooltip: null, //测量工具中显示的测量值
      continuePolygonMsg: '点击绘制多边形', //当用户正在绘制多边形时的提示信息文本
      continueLineMsg: '点击绘制测量线', //当用户正在绘制线时的提示信息文本
      helpMsg: '点击开始绘制', //当前默认提示信息
      listener: null,
      source: null, //图层数据源
    }
  },
  mounted() {},
  computed: {
    // vuex中的map
    ...mapState(['map']),
  },
  methods: {
    // 测量工具
    spaceMeasureFun(spaceMeasureType) {
      var that = this
      console.log(this.$store.state.map)
      //地图容器绑定鼠标移动事件，动态显示帮助提示框内容
      this.map.on('pointermove', this.pointerMoveHandler)
      //地图绑定鼠标移出事件，鼠标移出时为帮助提示框设置隐藏样式
      this.map.getViewport().addEventListener('mouseout', () => {
        that.helpTooltipElement.classList.add('hidden')
      })

      //1.创建画布
      //加载测量的绘制矢量层
      this.source = new ol.source.Vector() //图层数据源
      console.log(this.source)
      var vector = new ol.layer.Vector({
        source: this.source,
        style: new ol.style.Style({
          //图层样式
          fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 0.2)', //填充颜色
          }),
          stroke: new ol.style.Stroke({
            color: '#ffcc33', //边框颜色
            width: 2, // 边框宽度
          }),
          image: new ol.style.Circle({
            radius: 7,
            fill: new ol.style.Fill({
              color: '#ffcc33',
            }),
          }),
        }),
        name: '测量',
      })
      this.map.addLayer(vector)

      //2.创建画笔，LineString：距离，Polygon：面积
      if (spaceMeasureType == 'LineString') {
        this.draw = createDraw({
          source: this.source,
          type: spaceMeasureType,
          callback: drawEnd,
        })
      } else if (spaceMeasureType == 'Polygon') {
        this.draw = createDraw({
          source: this.source,
          type: spaceMeasureType,
          callback: drawEnd,
        })
      }
      //添加画笔
      this.map.addInteraction(this.draw)

      //3.绑定交互绘制工具开始绘制的事件
      this.draw.on(
        'drawstart',
        function (evt) {
          // set sketch
          sketch = evt.feature //绘制的要素
          /** @type {ol.Coordinate|undefined} */
          var tooltipCoord = evt.coordinate // 绘制的坐标
          //绑定change事件，根据绘制几何类型得到测量长度值或面积值，并将其设置到测量工具提示框中显示
          this.listener = sketch.getGeometry().on('change', function (evt) {
            var geom = evt.target //绘制几何要素
            var output
            if (geom instanceof ol.geom.Polygon) {
              output = that.formatArea(/** @type {ol.geom.Polygon} */ (geom)) //面积值
              tooltipCoord = geom.getInteriorPoint().getCoordinates() //坐标
            } else if (geom instanceof ol.geom.LineString) {
              output = that.formatLength(
                /** @type {ol.geom.LineString} */ (geom)
              ) //长度值
              tooltipCoord = geom.getLastCoordinate() //坐标
            }
            that.measureTooltipElement.innerHTML = output //将测量值设置到测量工具提示框中显示
            that.measureTooltip.setPosition(tooltipCoord) //设置测量工具提示框的显示位置
          })
        },
        this
      )

      //4.绑定交互绘制工具结束绘制的事件
      function drawEnd(e) {
        that.measureTooltipElement.className = 'tooltip tooltip-static' //设置测量提示框的样式
        that.measureTooltip.setOffset([0, -7])
        // unset sketch
        sketch = null //置空当前绘制的要素对象
        // unset tooltip so that a new one can be created
        that.measureTooltipElement = null //置空测量工具提示框对象
        that.createMeasureTooltip() //重新创建一个测试工具提示框显示结果
        ol.Observable.unByKey(this.listener)
        that.map.removeInteraction(that.draw) //移除画笔
        // 移除提示
        $(that.helpTooltipElement).remove()
        // 解除鼠标绑定
        that.map.un('pointermove', that.pointerMoveHandler)
      }
      //创建测量工具提示框
      this.createMeasureTooltip()
      //创建测量提示工具
      this.createHelpTooltip()
    },
    // 鼠标移动事件处理函数
    pointerMoveHandler(evt) {
      //如果是平移地图则直接结束
      if (evt.dragging) {
        return
      }
      //帮助提示信息
      /** @type {string} */
      this.helpMsg = '点击开始绘制'
      if (sketch) {
        //获取绘图对象的几何要素
        var geom = sketch.getGeometry()

        //如果当前绘制的几何要素是多边形，则将绘制提示信息设置为多边形绘制提示信息
        if (geom instanceof ol.geom.Polygon) {
          this.helpMsg = this.continuePolygonMsg //绘制多边形时提示相应内容
        } else if (geom instanceof ol.geom.LineString) {
          this.helpMsg = this.continueLineMsg //绘制线时提示相应内容
        }
      }
      if (this.helpTooltipElement) {
        //设置帮助提示要素的内标签为帮助提示信息
        this.helpTooltipElement.innerHTML = this.helpMsg
        //设置帮助提示信息的位置
        this.helpTooltip.setPosition(evt.coordinate)
      }
    },
    // 创建测量工具提示框
    createMeasureTooltip() {
      if (this.measureTooltipElement) {
        // console.log(this.measureTooltipElement);
        //如果已经存在帮助提示框则移除
        this.measureTooltipElement.parentNode.removeChild(
          this.measureTooltipElement
        )
      }
      this.measureTooltipElement = document.createElement('div')
      this.measureTooltipElement.className = 'tooltip tooltip-measure'
      this.measureTooltip = new ol.Overlay({
        id: '测量',
        element: this.measureTooltipElement,
        offset: [0, -15],
        positioning: 'bottom-center',
      })
      this.map.addOverlay(this.measureTooltip)
      // 将标注图层图层放到测量工具提示框中
      overLayerList.push(this.measureTooltip)
    },

    // 创建测量工具提示框
    createHelpTooltip() {
      this.helpTooltipElement = document.createElement('div')
      this.helpTooltipElement.className = 'tooltip hidden'
      this.helpTooltip = new ol.Overlay({
        id: '测量',
        element: this.helpTooltipElement,
        offset: [15, 0],
        positioning: 'center-left',
      })
      //将帮助提示的覆盖标注添加到地图中
      this.map.addOverlay(this.helpTooltip)
      // 将标注图层图层放到帮助提示框中
      overLayerList.push(this.helpTooltip)
    },

    /*
                 测量距离
     * @param {ol.geom.LineString} line
     * @return {string}
     * */
    formatLength(line) {
      var sphere = new ol.Sphere()
      //   这里直接默认使用地学方法测量
      let length = sphere.getLength(line, {
        projection: this.map.getView().getProjection(),
        radius: 6378137,
      })
      var output
      if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km' //换算成KM单位
      } else {
        output = Math.round(length * 100) / 100 + ' ' + 'm' //m为单位
      }
      return output //返回线的长度
    },

    /*
                 测量面积
     * @param {ol.geom.Polygon} polygon
     * @return {string}
     */
    formatArea(polygon) {
      //这里直接默认使用地学方法测量
      var sphere = new ol.Sphere()
      let area = Math.abs(
        sphere.getArea(polygon, {
          projection: this.map.getView().getProjection(),
          radius: 6378137,
        })
      ) //获取面积

      var output
      if (area > 10000) {
        output =
          Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>' //换算成KM单位
      } else {
        output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>' //m为单位
      }
      return output //返回多边形的面积
    },
    // 关闭测量
    removeMeasureFun() {
      /* 根据图层名移除图层 */
      this.removeLayerByName()
      /* 清除标注图层 */

      if (overLayerList != null && overLayerList.length > 0) {
        var len = overLayerList.length
        for (var i = len - 1; i >= 0; i--) {
          this.map.removeOverlay(overLayerList[i])
        }
      }
    },
    // 移除对应图层
    removeLayerByName() {
      let layers = this.map.getLayers().getArray() //获取所有图层
      /* 根据图层名移除图层 */
      let layer = layers.filter((item) => {
        return item.values_.name === '测量'
      })
      layer.forEach((item) => {
        this.map.removeLayer(item)
      })
    },
    // 导出图片
    exportImg() {
      this.map.once('postcompose', function (event) {
        var canvas = event.context.canvas
        canvas.toBlob(function (blob) {
          saveAs(blob, 'map.png')
        })
      })
      this.map.renderSync()
    },
  },
}
</script>

<style></style>
